// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.

namespace Microsoft.Samples.Commerce.Order.CommerceEntities
{
    using Microsoft.Commerce.Contracts;

    /// <summary>
    /// Represents a shipment associated with a specific order.
    /// </summary>
    public class Shipment : ICommerceEntity
    {
        /// <summary>
        /// defines the model name for this commerce entity
        /// </summary>
        public const string ModelNameDefinition = "Shipment";

        /// <summary>
        /// The commerce entity.
        /// </summary>
        private CommerceEntity commerceEntity;

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Shipment"/> class.
        /// </summary>
        public Shipment()
        {
            this.commerceEntity = new CommerceEntity(Shipment.ModelNameDefinition);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Shipment"/> class.
        /// </summary>
        /// <param name="commerceEntity">The commerce entity.</param>
        public Shipment(CommerceEntity commerceEntity)
        {
            this.commerceEntity = commerceEntity;
        }

        #endregion

        #region ICommerceEntity Members

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id of the entity.</value>
        public string Id
        {
            get { return this.commerceEntity.Id; }
            set { this.commerceEntity.Id = value; }
        }

        /// <summary>
        /// Gets or sets the type name of this object instance
        /// <remarks>Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type</remarks>
        /// </summary>
        /// <value></value>
        public string ModelName
        {
            get { return this.commerceEntity.ModelName; }
            set { this.commerceEntity.ModelName = value; }
        }

        /// <summary>
        /// Gets or sets this objects collection of Properties and their corresponding values
        /// </summary>
        /// <value></value>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Collection setting is required")]
        public CommercePropertyCollection Properties
        {
            get { return this.commerceEntity.Properties; }
            set { this.commerceEntity.Properties = value; }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the shipping discount amount.
        /// </summary>
        /// <value>The discount amount.</value>
        public decimal? DiscountAmount
        {
            get { return (decimal?)this.commerceEntity.GetPropertyValue(PropertyName.DiscountAmount); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.DiscountAmount, value ?? null); }
        }

        /// <summary>
        /// Gets or sets the collection of shipping discounts applied to the current shipment.
        /// </summary>
        /// <value>The discounts.</value>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Collection setting is required")]
        public CommerceRelationshipList Discounts
        {
            get { return this.commerceEntity.GetPropertyValue(RelationshipName.Discounts) as CommerceRelationshipList; }
            set { this.commerceEntity.SetPropertyValue(RelationshipName.Discounts, value); }
        }

        /// <summary>
        /// Gets or sets a collection of ids of line items associated with the current shipment.
        /// </summary>
        /// <value>The line item ids.</value>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819", Justification = "This needs to be an array for consistent serialization")]

        public string[] LineItemIds
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.LineItemIds) as string[]; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.LineItemIds, value); }
        }

        /// <summary>
        /// Gets or sets the shipping address associated with the current shipment.
        /// </summary>
        /// <value>The shipping address.</value>
        public string ShippingAddressId
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.ShippingAddressId) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.ShippingAddressId, value); }
        }

        /// <summary>
        /// Gets or sets the shipping method associated with the current shipment.
        /// </summary>
        /// <value>The shipping method id.</value>
        public CommerceRelationship ShippingMethod
        {
            get { return this.commerceEntity.GetPropertyValue(RelationshipName.ShippingMethod) as CommerceRelationship; }
            set { this.commerceEntity.SetPropertyValue(RelationshipName.ShippingMethod, value); }
        }

        /// <summary>
        /// Gets or sets the status code of the current shipment.
        /// </summary>
        /// <value>The status.</value>
        public string StatusCode
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.StatusCode) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.StatusCode, value); }
        }

        /// <summary>
        /// Gets or sets the total shipping cost for the current shipment.
        /// </summary>
        /// <value>The total.</value>
        public decimal? Total 
        {
            get { return (decimal?)this.commerceEntity.GetPropertyValue(PropertyName.Total); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.Total, value ?? null); }
        }

        /// <summary>
        /// Gets or sets a value that uniquely identifies a shipment.
        /// </summary>
        /// <value>The tracking number.</value>
        /// <remarks>Normally, this value is provided by the shipping company.</remarks>
        public string TrackingNumber
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.TrackingNumber) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.TrackingNumber, value); }
        }

        #endregion

        #region Implicit operators
        /// <summary>
        /// Toes the user profile.
        /// </summary>
        /// <param name="commerceEntity">The commerce entity.</param>
        /// <returns></returns>
        public static implicit operator Shipment(CommerceEntity commerceEntity)
        {
            System.Diagnostics.Debug.Assert(Shipment.ModelNameDefinition.Equals(commerceEntity.ModelName), "Unexpected model name");
            return new Shipment(commerceEntity);
        }
        #endregion

        /// <summary>
        /// Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type using <see cref="ModelName"/>
        /// </summary>
        /// <returns>This instances base type</returns>
        public CommerceEntity ToCommerceEntity()
        {
            return this.commerceEntity;
        }

        #region Property key names

        /// <summary>
        /// Names of the properties exposed by this commerce entity.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Needed for external access"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Cannot make it private as it cannot be derived from")]
        public class PropertyName : CommerceEntity.PropertyName
        {
            #region Constants

            /// <summary>
            /// The name of the DiscountAmount property for a Shipment.
            /// </summary>
            public const string DiscountAmount = "DiscountAmount";

            /// <summary>
            /// The name of the LineItemIds property.
            /// </summary>
            public const string LineItemIds = "LineItemIds";

            /// <summary>
            /// The name of the ShippingAddressId property for a Shipment.
            /// </summary>
            public const string ShippingAddressId = "ShippingAddressId";

            /// <summary>
            /// The name of the StatusCode property for a Shipment.
            /// </summary>
            public const string StatusCode = "StatusCode";

            /// <summary>
            /// The name of the Total property for a Shipment.
            /// </summary>
            public const string Total = "Total";

            /// <summary>
            /// The name of the TrackingNumber property for a Shipment.
            /// </summary>
            public const string TrackingNumber = "TrackingNumber";

            #endregion
        }

        /// <summary>
        /// Class defining Properties of Items that may be related to a Shipment.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "Required because of API specification (i.e. DataContract design)")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Needed for external access"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Cannot make it private as it cannot be derived from")]
        public class RelationshipName
        {
            /// <summary>
            /// The name of the ShippingMethod property for a Shipment.
            /// </summary>
            public const string ShippingMethod = "ShippingMethod";

            /// <summary>
            /// The name of the Discounts property for an item related to a Shipment.
            /// </summary>
            public const string Discounts = "Discounts";
        }

        #endregion
    }
}
